package com.scau.os.course_manager;

import com.scau.os.course_manager.bean.DeviceAllocationTable;
import com.scau.os.course_manager.bean.PCB;
import com.scau.os.course_manager.bean.PSW;
import com.scau.os.course_manager.bean.Register;
import com.scau.os.extension.EventSystem;

import java.util.HashMap;

public class EmulationCPU {
    private PCB pcb;
    private Register register;
    private int result=0;
    private int cnt=0;
    private DeviceAllocationTable deviceAllocationTable;
    private  final byte assignInstruction =0 ; // For x=?
    private  final byte incrementInstruction =1; // For x++
    private  final byte specialCommandInstruction =2 ; // For !?
    private  final byte endInstruction = (byte) 3; // For end
    private byte operatorMask;
    private byte operatorValue;
    private String[] devices={"A","B","C"};

    public void CPU(){
        //检查是否有中断
        PSW psw=pcb.register.psw;
        if (psw.ioTrap) {
            psw.ioTrap=false;
            psw.timeoutTrap=false;
            EventSystem.instance.SendEvent("applyDevice",deviceAllocationTable,false);
            //记得在解除阻塞之后更新psw的值
        }else if (psw.timeoutTrap) {
            psw.timeoutTrap=false;
            EventSystem.instance.SendEvent("timeSlideOver",null,false);
        }else if(psw.endTrap){
            EventSystem.instance.SendEvent("executeFinish",null,false);
            EventSystem.instance.SendEvent("ExecuteResultUpdate",String.valueOf(result),false);
        }

        EventSystem.instance.SendEvent("RunningPCBUpdate",pcb.processID);
        if(pcb.isIdle){
            EventSystem.instance.SendEvent("IntermediateResultUpdate","空闲进程什么也不干",false);
            //EventSystem.instance.SendEvent("ExecuteResultUpdate","空闲进程什么也不干",false);
            EventSystem.instance.SendEvent("RunningCommandUpdate","空闲进程什么也不干",false);
        }
        else {
            //回复现场
            result=pcb.register.ax;

            if(pcb.register.address==null||pcb.register.address.instruction.size()<=pcb.register.address.instructionCount){
                System.err.println("PCB指令错误，出现非法结尾");
            }else {
                executeInstruction(pcb.register.address.instruction.get(pcb.register.address.instructionCount++));
            }

            //保存现场
            pcb.register.ax=result;
            EventSystem.instance.SendEvent("IntermediateResultUpdate",String.valueOf(result),false);
        }

        EventSystem.instance.SendEvent("RelativeClockUpdate",6-cnt,false);
        cnt++;
        if(cnt>=6){
            pcb.register.psw.timeoutTrap=true;
            cnt=0;
        }
    }
    private void executeInstruction(Byte instruction) {
        operatorMask = (byte) ((instruction & 0b11000000)>>6);
        operatorValue = (byte) (instruction & 0b00111111);
        if (operatorMask == endInstruction) {
            EventSystem.instance.SendEvent("RunningCommandUpdate","end");
            EventSystem.instance.SendEvent("IntermediateResultUpdate","end");
            EventSystem.instance.SendEvent("ExecuteResultUpdate",String.valueOf(result));
            end();
        } else if (operatorMask == assignInstruction) {
            assignValue(operatorValue);
            EventSystem.instance.SendEvent("RunningCommandUpdate","x="+(int)operatorValue);
        } else if (operatorMask == incrementInstruction) {

            if((int)operatorValue!=1){
                EventSystem.instance.SendEvent("RunningCommandUpdate","x--");
                increment(-1);
            }else {
                EventSystem.instance.SendEvent("RunningCommandUpdate","x++");
                increment(1);
            }
        } else if (operatorMask == specialCommandInstruction) {
            int index=(operatorValue & 0b00110000) >> 4;
            if(index>=devices.length||index<0){
                System.err.println("非法的设备编号"+index);
            }else {
                String device = devices[index];
                int time = (operatorValue & 0b00001111);
                specialCommand(device, time);
                EventSystem.instance.SendEvent("RunningCommandUpdate","!"+device+time);
            }

        } else {
            System.out.println("Invalid instruction in CPU execute");
        }
    }

    private void assignValue(int value) {
        result=value;
    }
    private void increment(int value) {
        result+=value;
    }
    private void specialCommand(String device, int time) {
        pcb.register.psw.ioTrap=true;
        deviceAllocationTable=new DeviceAllocationTable(device,time,pcb);
    }
    private void end() {
        pcb.register.psw.endTrap=true;
    }
    /**
     * 更换进程，同时保存上一次的进程寄存器和加载这次
     * 要用的进程的现场
     */
    public void setPcb(PCB pcb) {
        this.pcb = pcb;
        register=pcb.register;
        cnt=0;
    }

    public PCB getPcb() {
        return pcb;
    }

}
